﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using StackExchange.Redis;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using WebApplication_JWTDemo.Common;
using Newtonsoft.Json;

namespace WebApplication_JWTDemo.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    [Authorize]
    public class TestController : ControllerBase
    {
        private readonly IConfiguration _config;
        private readonly IDatabase _redisDatabase;
        private readonly JwtSettings _jwtSettings;
        public TestController(IConfiguration config, IConnectionMultiplexer redis)
        {
            _config = config;
            _redisDatabase = redis.GetDatabase();
            _jwtSettings= _config.GetSection("JwtSettings").Get<JwtSettings>();
        }

        [HttpGet]
        [AllowAnonymous]
        public IActionResult Login(string? loginName, string? password)
        {
            if (loginName == "1" && password == "1")
            {
                return Unauthorized();
            }
            var token = CreateTokenString(loginName, 1);


            // 登录判定
            return Ok(token);
        }
        /// <summary>
        /// 生成 JWT Token（令牌）
        /// </summary>
        /// <returns></returns>
        private TokenResponse CreateTokenString(string? loginName, int userId)
        {
            //私钥
            var secretByte = Encoding.UTF8.GetBytes(_jwtSettings.SigningKey);
            // 非对称加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            // 使用256 生成数字签名
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            //Claims 指用户的信息  用户名 权限 用户id  角色ID   
            var claims = new[]
            {
                new Claim("UserName",loginName),
                new Claim("UserId",userId.ToString())
            };
            // 生成Token
            var token = new JwtSecurityToken(
                issuer: _jwtSettings.Issuer,
                audience: _jwtSettings.Audience,
                expires: DateTime.UtcNow.AddMinutes(_jwtSettings.AccessTokenExpirationMinutes), // 过期时间
                signingCredentials: signingCredentials,
                claims: claims
            );
            // 生成token 字符串
            var strToken = new JwtSecurityTokenHandler().WriteToken(token);

            // 创建refresh token
            var refreshToken = new RefreshToken
            {
                Token = Guid.NewGuid().ToString("N"),
                Expires = DateTime.UtcNow.AddDays(_jwtSettings.RefreshTokenExpirationDays),
                Created = DateTime.UtcNow,
                UserId = userId
            };
            //存入redis
            _redisDatabase.StringSet(userId.ToString() + "refreshToken", JsonConvert.SerializeObject(refreshToken));
            _redisDatabase.StringSet(userId.ToString() + "AccessToken", strToken);
            // 返回token响应
            return new TokenResponse
            {
                AccessToken = strToken,
                RefreshToken = refreshToken.Token,
                ExpiresIn = (int)TimeSpan.FromMinutes(_jwtSettings.AccessTokenExpirationMinutes).TotalSeconds
            };
        }
        /// <summary>
        /// token过期 刷新token
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("refresh")]
        [AllowAnonymous]
        public async Task<IActionResult> Refresh([FromBody] RefreshTokenRequest request)
        {
            if (string.IsNullOrEmpty(request.AccessToken) || string.IsNullOrEmpty(request.RefreshToken))
                return BadRequest();

            //// 从过期的access token中获取principal
            var principal = GetPrincipalFromExpiredToken(request.AccessToken);
            if (principal == null)
                return BadRequest("Invalid token");

            var userId = int.Parse(principal.FindFirst("UserId").Value);
            var userName = principal.FindFirst("UserName").Value;

            // 验证refresh token是否有效（应从数据库或其他存储中验证）
            var storedRefreshTokenJson = _redisDatabase.StringGet(userId.ToString() + "refreshToken");
            var storedRefreshToken = JsonConvert.DeserializeObject<RefreshToken>(storedRefreshTokenJson);
            if (storedRefreshToken == null || storedRefreshToken.Expires < DateTime.UtcNow)
                return BadRequest("Invalid refresh token");

            // 获取用户信息
            //var user = await _userService.GetById(userId);
            //if (user == null)
            //    return BadRequest("User not found");

            // 生成新的token
            var newToken = CreateTokenString(userName, userId);

            return Ok(newToken);
        }

        /// <summary>
        ///  解析token
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="SecurityTokenException"></exception>
        private ClaimsPrincipal? GetPrincipalFromExpiredToken(string token)
        {
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateAudience = false,
                ValidateIssuer = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SigningKey)),
                ValidateLifetime = false // 这里我们就是要处理过期的token
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken);

            if (securityToken is not JwtSecurityToken jwtSecurityToken ||
                !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
                throw new SecurityTokenException("Invalid token");

            return principal;
        }


        [HttpGet]
        public string GetData()
        {
            return "请求成功!";
        }
    }
}
